/*
 * EventQueue.java
 *
 * Created on 2004/04/19 +0900
 *
 * $Revision: 38 $
 * $Date: 2008-10-11 08:48:45 +0000 (Sat, 11 Oct 2008) $
 */

package org.gikolet.framework.ui;

import java.util.Enumeration;

import org.gikolet.framework.Toolkit;
import org.gikolet.framework.request.ProxyRequest;
import org.gikolet.framework.request.Request;
import org.gikolet.framework.request.RequestManager;
import org.gikolet.framework.request.RequestProcesser;
import org.gikolet.framework.request.RequestProcesserProvider;
import org.gikolet.framework.request.RequestTicket;

/**
 * @author Tetsutaro (latest modification by $Author: tetsutaro.ss $)
 * @version $Revision: 38 $ $Date: 2008-10-11 08:48:45 +0000 (Sat, 11 Oct 2008) $
 */
public class EventQueue {
    private Display display;

    private RequestProcesserProvider requestProcesserProvider;

    private RequestManager validateRequestManager;
    private RequestManager paintRequestManager;
    private RequestManager keyActionRequestManager;

    EventQueue(Display display) {
	this.display = display;

	// 必要時のみ取得のため
	this.requestProcesserProvider = new RequestProcesserProvider() {
	    public RequestProcesser getRequestProcesser() {
		return Toolkit.getRequestProcesser();
	    }
	};

	this.validateRequestManager = new RequestManager(this.requestProcesserProvider);
	this.paintRequestManager = new RequestManager(this.requestProcesserProvider);
	this.keyActionRequestManager = new RequestManager(this.requestProcesserProvider);
    }

    public void repaint(int x, int y, int width, int height) {
	Enumeration tickets = this.paintRequestManager.tickets();

	while (tickets.hasMoreElements()) {
	    RequestTicket ticket = (RequestTicket) tickets.nextElement();
	    PaintRequest request = (PaintRequest) ticket.getRequest();

	    int minX = (request.x > x) ? x : request.x;
	    int minY = (request.y > y) ? y : request.y;
	    int maxX = (request.x + request.width > x + width) ? request.x
		    + request.width : x + width;
	    int maxY = (request.y + request.height > y + height) ? request.y
		    + request.height : y + height;
	    x = minX;
	    y = minY;
	    width = maxX - minX;
	    height = maxY - minY;

	    ticket.cancel();
	    break;
	}
	Request request = new PaintRequest(x, y, width, height);

	this.paintRequestManager.invoke(request);
    }

    public synchronized void validate(Container source, boolean direct) {
	Enumeration tickets = this.validateRequestManager.tickets();

	vfind: while (tickets.hasMoreElements()) {
	    RequestTicket ticket = (RequestTicket) tickets.nextElement();
	    LayoutRequest request = (LayoutRequest) ticket.getRequest();

	    Container vroot;

	    vroot = source;
	    do {
		if (vroot == request.source) {
		    ticket.cancel();
		    source = vroot;
		    break vfind;
		}
		vroot = vroot.getParentValidRoot();
	    } while (vroot != null);

	    vroot = request.source;
	    do {
		if (vroot == source) {
		    ticket.cancel();
		    break vfind;
		}
		vroot = vroot.getParentValidRoot();
	    } while (vroot != null);
	}

	if (direct) {
	    this.display.layout(source);
	} else {
	    Request request = new LayoutRequest(source);

	    this.validateRequestManager.invoke(request);
	}
    }

    public synchronized void keyAction(int keyType, int keyCode) {
	Enumeration tickets = this.keyActionRequestManager.tickets();

	while (tickets.hasMoreElements()) {
	    KeyActionRequest request = (KeyActionRequest) tickets.nextElement();
	    if (request.keyActionType == keyType && request.keyCode == keyCode) {
		return;
	    }
	}
	Request request = new KeyActionRequest(keyType, keyCode);

	this.keyActionRequestManager.invoke(request);
    }

    public void invoke(Runnable run) {
	Request request = new ProxyRequest(run, false);

	this.requestProcesserProvider.getRequestProcesser().invoke(request);
    }

    public void invokeAndWait(Runnable run) throws InterruptedException, Throwable {
	Request request = new ProxyRequest(run, false);

	this.requestProcesserProvider.getRequestProcesser().invokeAndWait(request);
    }

    class KeyActionRequest extends ProxyRequest {
	int keyActionType;
	int keyCode;

	public KeyActionRequest(int keyActionType, int keyCode) {
	    super(false);

	    this.keyActionType = keyActionType;
	    this.keyCode = keyCode;
	}

	protected synchronized void executeCore() {
	    EventQueue.this.display.keyAction(this.keyActionType, this.keyCode);
	}
    }

    class PaintRequest extends ProxyRequest {
	int x;
	int y;
	int width;
	int height;

	public PaintRequest(int x, int y, int width, int height) {
	    super(false);

	    this.x = x;
	    this.y = y;
	    this.width = width;
	    this.height = height;
	}

	protected synchronized void executeCore() {
	    EventQueue.this.display.paint(this.x, this.y, this.width, this.height, false);
	}
    }

    class LayoutRequest extends ProxyRequest {
	Container source;

	public LayoutRequest(Container source) {
	    super(false);

	    this.source = source;
	}

	protected synchronized void executeCore() {
	    EventQueue.this.display.layout(this.source);
	}
    }
}
